/*
 * Programa
 */

#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <ctype.h>
#include <unistd.h>
#include <math.h>
#include <stdio.h>
#include "odump.h"

#define END_OF_STRING '\0'
#define ERROR_PARAMETROS "Use -h para ver el help\n"
#define ERROR_ARCHIVOS "Error con los archivos pasados como argumento\n"
#define EMPTY -2
#define MODO_OCTAL 1
#define MODO_BINARY 2

void mostrarMenu() {
	printf("Usage:\n");
	printf("tp0 -h\n");
	printf("tp0 -V\n");
	printf("tp0 [options]\n");
	printf("Options:\n");
	printf("-h, --help\n");
	printf("Print this information.\n");
	printf("-V, --version\n");
	printf("Print version and quit.\n");
	printf("-O, --octal\n");
	printf("Octal dump mode: encode the input (binary file) in octal format (default).\n");
	printf("-b, --binary\n");
	printf("Binary mode: decode the input (octal dump file) in binary format.\n");	printf("-h, --help\n");
	printf("-i, --input\n");
	printf("Path to input file (defaults to stdin).\n");
	printf("-o, --output\n");
	printf("Path to output file (defaults to stdout).\n");
	printf("-l --length\n");
	printf("Number of octal bytes per line (line length) at the output in octal dump mode (0 = default = no limit).\n");
	printf("-d --delimiter\n");
	printf("Delimiter between octal bytes. Could be a string, not only a single byte. Used as delimiter for octal output and input files (default: none).\n");

	printf("Examples:\n");
	printf("tp0\n");
	printf("tp0 -i -\n");
	printf("tp0 -i - -o - -O\n");
	printf("tp0 -b\n");
	printf("tp0 -i /dev/random -o /tmp/random-octaldump -l 12\n");

	exit(0);
}


void convertirEntrada(int argc, char ** argv,char **f1,char **f2,int * mode,char **delimiter, int *len) {
	int opt = 0;
	int option_index = 0;
	static struct option long_options[] = {
			{ "help", no_argument, 0,'h' },
			{ "version", no_argument, 0, 'V' },
			{ "octal", no_argument, 0, 'O' },
			{ "binary", no_argument, 0, 'b' },
			{ "input", required_argument, 0, 'i' },
			{ "output", required_argument, 0, 'o' },
			{ "length", required_argument, 0, 'l' },
			{ "delimiter", required_argument, 0, 'd' },
			{ 0, 0, 0, 0 }
	};

	while ((opt = getopt_long(argc, argv, "hVObi:o:l:d:?", long_options, &option_index)) != -1) {
		switch (opt) {
			case 'h':
				mostrarMenu();
				break;
			case 'V':
				printf("Tp0 Organizacion de Computadoras \n\n");
				exit(0);
				break;
			case 'O':
				*mode=MODO_OCTAL;
				break;
			case 'b':
				*mode=MODO_BINARY;
				break;
			case 'i':
				*f1 = optarg;
				//printf("IN: %s\n",optarg);
				break;
			case 'o':
				*f2 = optarg;
				//printf("OUT: %s\n",optarg);
				break;
			case 'd':{
				*delimiter = optarg;
				break;
			}
			case 'l':
				*len = atoi(optarg);

				break;
			case '?':
				fprintf(stderr, "Error - No existe la opcion: `%c'\n\n", optopt);
				exit(0);
				break;
			default:
				mostrarMenu();
				break;
		}
	}
}



int openFile(FILE** file,char* location,FILE* defaultFile,char * openMode){
	if(location == NULL){
		*file = defaultFile;
	}else{
		*file=fopen(location,openMode);

		location = NULL;

		if (*file == NULL) {
			printf(ERROR_ARCHIVOS);
			return -1;
		}
	}

	return 0;
}

int abrirArchivos(int argc,char **argv,FILE **f1,FILE **f2,char* file1,char* file2){

	if (openFile(f1,file1,stdin,"rb"))
		return -1;

	if (openFile(f2,file2,stdout,"wb"))
		return -1;

	return 0;
}


int main(int argc,char** argv){
	FILE *f1,*f2;
	char *file1,*file2;
	char * delimiter="";
	int len=0;
	int mode;
	int error=0;
	f1=f2=NULL;
	file1=file2=NULL;
	error=0;

	struct odump_opts opciones;
	//inicializo opciones
	opciones.length=0;
	opciones.delim="";

	convertirEntrada(argc,argv,&file1,&file2,&mode,&delimiter,&len);

	//-----------------------------
	if (abrirArchivos(argc,argv,&f1,&f2,file1,file2) < 0)
		return -1;

	opciones.length=len;
	opciones.delim=delimiter;

	if(mode==MODO_BINARY){
		error=odump_decode(fileno(f1),fileno(f2), &opciones);
	}else{
		error=odump_encode(fileno(f1),fileno(f2), &opciones);
	}

	fclose(f1);
	fclose(f2);
	return error;

}

